/*
 * util.h
 *
 *  Created on: Sep 26, 2013
 *      Author: killerg
 */

#ifndef UTIL_H_
#define UTIL_H_

#include "json/json.h"
#include "rapidjson/document.h"
namespace rj = rapidjson;

#include <list>
#include <string>
#include <vector>

// 取得路径
const char* get_path();
const char* get_thisdir();
const char* get_deploy();

// 字符串长度不超过1024
const char* fmt_cstr(const char* fmt, ...);
std::string fmt_str(const char* fmt, ...);
const char* to_cstr(const Json::Value &json);
std::string to_str(const Json::Value &json);
Json::Value to_json(const char* str);
Json::Value to_json(const std::string &str);

const char* to_cstr(const rj::Document &doc);
std::string to_str(const rj::Document &doc);
bool to_rj(const char* str, rj::Document &doc);
bool to_rj(const std::string &str, rj::Document &doc);


// 读取文件中读取json
const char* load_file(const char* path);
bool save_file(const char* path, const char* data);

// 分割字符串
void split(const std::string &str, const std::string &delimiter, std::vector<std::string> &dest);

template<typename IDT>
void id_list(const Json::Value &one, std::vector<IDT> &ids) {
    if (one.empty() || one.isNull())
        return;

    ids.clear();

    std::vector<std::string> str_ids;
    std::string str = one.asString();
    if (str.empty())
        return;
    std::string delim = ",";
    split(str, delim, str_ids);

    for (auto itr = str_ids.begin(); itr != str_ids.end(); ++itr) {
        ids.push_back(IDT(atof(itr->c_str())));
    }
}

// close range random number
inline int32_t random(int32_t cbegin, int32_t cend) {
    return cbegin + rand()%(cend - cbegin + 1);
}

// 成功率10000
inline bool prob(int32_t prob) {
    return random(0, 9999) < prob;
}

inline int32_t random(int32_t &stepseed) {
	stepseed = stepseed * 1103515245L + 12345L;
	return (stepseed >> 1) & 2147483647L;
}

inline int32_t random(const std::vector<std::pair<int32_t, int32_t> > &item) {
    int32_t rand_num = random(0, 10000-1);
    for (int i=0; i<int(item.size()); ++i) {
        rand_num -= item[i].second;
        if (rand_num < 0)
            return item[i].first;
    }

    return -1;
}

// return index;
inline int32_t random(const int32_t* prob, int num) {

    std::vector<std::pair<int32_t, int32_t> > items;
    for (int i=0; i<num; ++i) {
        int32_t index = i;
        int32_t item_prob = prob[i];
        items.emplace_back(index, item_prob);
    }

    return random(items);
}

inline int32_t my_rand_r(uint32_t* seed) {
   	*seed = *seed * 1103515245L + 12345L;
    return (*seed >> 1) & 2147483647L;
}

// vec first prob second id
// return first
inline int32_t random_item(int32_t seed, int step, const std::vector<std::pair<int32_t, int32_t> > &item) {
    unsigned int holder = seed;
    int32_t rand_num = 0;
    for (int i=0; i<step; ++i)
    	rand_num = my_rand_r(&holder);

    rand_num %= 10000;

    for (int i=0; i<int(item.size()); ++i) {
        rand_num -= item[i].second;
        if (rand_num < 0)
            return item[i].first;
    }

    return -1;
}

template<typename ValueT>
inline ValueT cut(ValueT value, ValueT cbegin, ValueT cend) {
    return std::min(cend, std::max(cbegin, value));
}

template<typename T>
inline void safe_del(T* &ptr) {
    if (NULL == ptr)
        return;

    delete ptr;
    ptr = NULL;
}

template<typename T>
inline void safe_del_array(T* &ptr) {
    if (NULL == ptr)
        return;

    delete[] ptr;
    ptr = NULL;
}

#include <sys/socket.h>
#include <netinet/tcp.h>

inline bool set_keepalive(int fd) {
    int keep_alive = 1;
    if (0 != setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keep_alive, sizeof(keep_alive)))
        return false;

    keep_alive = 6;
    if (0 != setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &keep_alive, sizeof(keep_alive)))
        return false;

    keep_alive = 5;
    if (0 != setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &keep_alive, sizeof(keep_alive)))
        return false;

    keep_alive = 3;
    if (0 != setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &keep_alive, sizeof(keep_alive)))
        return false;

    return true;
}

#include <sys/signal.h>
inline void on_signal(int32_t sig, void(*handler)(int)) {
    struct sigaction act;
    bzero(&act, sizeof(act));
    act.sa_handler = handler;
    act.sa_flags = SA_RESTART;
    sigaction(sig, &act, NULL);
}

inline void sig_ignore(int sig) {
	struct sigaction sa;
    sa.sa_handler = SIG_IGN;
    sa.sa_flags = 0;

    if (sigemptyset(&sa.sa_mask) == -1 || sigaction(sig, &sa, 0) == -1) {
        return;
    }
    return;
}

#include <openssl/hmac.h>
#include <openssl/md5.h>
#include <string.h>
#include <stdio.h>

inline const char* hex_to_cstr(uint8_t* buf, int len) {
    static char ret_buf[2048];
    for (int i=0; i<len; ++i)
        sprintf(ret_buf+i*2, "%02x", buf[i]);

    return ret_buf;
}

inline const char* Md5(const char* str) {
    uint8_t* buf = MD5((uint8_t*)str, strlen(str), NULL);
    return hex_to_cstr(buf, 16);
}

inline const char* Sha1(const char* str, const char* key, int str_len = -1, int key_len = -1) {
    if (str_len <= 0)
        str_len = strlen(str);
    if (key_len <= 0)
        key_len = strlen(key);
    uint32_t res_len = 0;
    uint8_t* buffer = HMAC(EVP_sha1(), (void*)key, key_len, (uint8_t*)str, str_len, NULL, &res_len);
    return hex_to_cstr(buffer, res_len);
}

#include <zlib.h>
inline int32_t Crc(const char* str, int32_t len = -1) {
    return crc32(0, (uint8_t*)str, len>0?len:strlen(str));
}
inline int32_t Crc(const std::string &str) {
    return crc32(0, (uint8_t*)str.c_str(), str.length());
}

#include <stdarg.h>

enum ELogMask {
    E = 1,
    W = 2,
    I = 4,
    T = 8,
    C = 16,
};

typedef int(*log_cb_t)(int mask, const char* fmt, ...);
typedef int(*vlog_cb_t)(int mask, const char* fmt, va_list arg);

extern log_cb_t util_logcb;
extern vlog_cb_t util_vlogcb;

#define UTIL_VLOG(mode, fmt, arg)     (NULL==util_logcb)?0:util_vlogcb(mode, #mode ":" fmt "\n", arg)
#define UTIL_LOG(mode, fmt, a...)     (NULL==util_logcb)?0:util_logcb(mode, #mode ":" fmt "\n", ##a)

const char* encode(const char* data);
const char* decode(const char* data);

//utf8字符长度1-6，可以根据每个字符第一个字节判断整个字符长度
//0xxxxxxx
//110xxxxx 10xxxxxx
//1110xxxx 10xxxxxx 10xxxxxx
//11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
//111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
//1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
//定义查找表，长度256，表中的数值表示以此为起始字节的utf8字符长度
extern const unsigned char utf8_look_for_table[];
/*
 * 计算str字符数目
 */
#define UTFLEN(x)  utf8_look_for_table[(x)]
inline int getUTF8Length(const char *str)
    {
    int clen = strlen(str);
    int len = 0;

    for(const char *ptr = str; *ptr!=0&&len<clen; len++, ptr+=UTFLEN((unsigned char)*ptr));

    return len;
}

extern const char* base64_decode(const char *src, int srcLen);

// path must be "/path/to"
void* shm_get(const char* path, size_t size);
void* shm_new(const char* path, size_t size);
void shm_free(const char* path, size_t size, void* data);

// Run Sleep Disk Zombie Trace Waitpage
char get_proc_status(int pid);


struct SvcData {
	enum EStatus {
		Noexist = 0,
		Initing,
		Running,
		Shutting,
	};

	char prefix[32];
	time_t refresh;
	EStatus status;
	int32_t pid;
	bool shut;
};

typedef void (*run_cb_t)(SvcData* data);
bool svc_ctrl(int argc, char** argv, run_cb_t run_cb);

std::string execute(const char* cmd);

#endif /* UTIL_H_ */
